﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPMS.Log.Core;
using SPMS.Log.Utility;
using SPMS.Utility;

namespace SPMS.Log.Appender
{
    /// <summary>
    /// 抽象日志记录器
    /// </summary>
    /// <remarks>提供了日志记录器的默认基类实现</remarks>
    /// <history>
    /// [zanezeng]               2009/9/25 14:58    创建
    /// </history>
    public abstract class AbstractLogAppender : ILogAppender
    {
        #region ---Constructor

        /// <summary>
        /// 初始化类型<see cref="AbstractLogAppender"/>的新实例
        /// </summary>
        /// <param name="name">当前日志记录器的名称</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="name"/>为空字符串或者为<c>null</c>引用。</exception>
        /// <history>
        /// [zanezeng]               2009/10/10 10:12    创建
        /// </history>
        public AbstractLogAppender(string name)
        {
            //断言参数
            ArgumentAssert.AssertStringArgumentNotNullOrEmpty(name, "name");

            //设置名称
            this.m_Name = name;
        }

        /// <summary>
        /// 析构函数，用于释放<see cref="AbstractLogAppender"/>实例的非托管资源
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/9 11:37    创建
        /// </history>
        ~AbstractLogAppender()
        {
            //关闭日志记录器
            this.Close();
        }

        #endregion

        #region ---ILogAppender

        /// <summary>
        /// 获得日志追加器的名称
        /// </summary>
        /// <value>日志追加器的名称</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:29    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/11/24 15:16    创建
        /// </history>
        public string Name
        {
            get
            {
                return this.m_Name;
            }
        }

        /// <summary>
        /// 获得或者设置设置当前日志输出器是否可用
        /// </summary>
        /// <value>
        /// 	<c>true</c>：日志输出器可用<br/>
        /// 	<c>false</c>：日志输出器不可用
        /// </value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:27    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public bool IsEnabled
        {
            get
            {
                return this.m_IsEnabled;
            }
            set
            {
                this.m_IsEnabled = value;
            }
        }

        /// <summary>
        /// 获得一个值，该值用于判断日志输出器是否已经关闭
        /// </summary>
        /// <value>
        /// 	<c>true</c>：日志输出器已经关闭<br/>
        /// 	<c>false</c>：日志输出器没有关闭
        /// </value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:05    创建
        /// </history>
        public bool IsClosed
        {
            get
            {
                return this.m_IsClosed;
            }
        }

        /// <summary>
        /// 向当前的日志输出器中添加一条日志记录
        /// </summary>
        /// <param name="entry">要添加到当前日志输出器中的日志记录</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/22 17:42    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public virtual void Append(LogEntry entry)
        {
            //判断日志条目是否为NULL
            if (null == entry)
            {
                //如果日志条目为NULL，则直接返回
                return;
            }

            //判断当前输出器是否可用
            if (!this.IsEnabled)
            {
                //如果当前日志输出器不可用，则直接返回
                return;
            }

            //判断日志输出器是否已经关闭
            if (this.IsClosed)
            {
                //处理错误
                this.ErrorHandler.HandleError(string.Format(Log.Properties.Resources.MSG_APPENDER_CLOSED, this.Name));

                //如果关闭则直接返回
                return;
            }

            //输出日志
            try
            {
                //判断日志级别是否允许
                if (!this.IsLevelAllowed(entry.Level))
                {
                    //如果日志级别不允许，则直接返回
                    return;
                }

                //判断日志条目是否允许
                if (!this.IsLogEntryAllowed(entry))
                {
                    //如果日志条目不允许，则直接返回
                    return;
                }

                //通知准备输出日志
                if (OnBeforeAppend(entry))
                {
                    //创建同步区域
                    using (this.SynchronizationContext.Synchronize(this))
                    {
                        //输出日志
                        this.OnAppend(entry);

                        //判断是否自动强制写入数据
                        if (this.AutoFlush)
                        {
                            //如果是自动强制写入数据，则强制写入数据
                            this.Flush();
                        }
                    }

                    //通知日志条目被输出
                    this.OnAfterAppend(entry, false);
                }
                else
                {
                    //通知日志条目被取消
                    this.OnAfterAppend(entry, true);
                }
            }
            catch (Exception ex)
            {
                //处理错误
                this.ErrorHandler.HandleError(string.Format(Log.Properties.Resources.MSG_APPENDER_APPEND_FAIELD, this.Name), ex);
            }
        }

        /// <summary>
        /// 关闭当前日志记录器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 14:52    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public void Close()
        {
            //判断日志输出器是否已经关闭
            if (this.m_IsClosed)
            {
                //如果已经关闭，则直接返回
                return;
            }

            //设置已经关闭
            this.m_IsClosed = true;

            try
            {
                //关闭
                this.OnClose();
            }
            catch (Exception ex)
            {
                //处理错误
                this.ErrorHandler.HandleError(string.Format(Log.Properties.Resources.MSG_APPENDER_CLOSE_FAILED, this.Name), ex);
            }
        }

        #endregion

        #region ---ILogFilterAttachable

        /// <summary>
        /// 获得关联的所有日志过滤器
        /// </summary>
        /// <value>关联的所有日志过滤器</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:11    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public ILogFilter[] Filters
        {
            get
            {
                return this.m_LogFilterAttachable.Filters;
            }
        }

        /// <summary>
        /// 添加日志过滤器
        /// </summary>
        /// <param name="filter">要添加的日志过滤器</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:12    创建
        /// </history>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="filter"/>为<c>Null</c></exception>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public void AddFilter(ILogFilter filter)
        {
            this.m_LogFilterAttachable.AddFilter(filter);
        }

        /// <summary>
        /// 删除指定日志过滤器
        /// </summary>
        /// <param name="filter">要删除的日志过滤器</param>
        /// <returns>
        /// 	<c>true</c>：删除成功<br/>
        /// 	<c>false</c>：删除失败
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:14    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public bool RemoveFilter(ILogFilter filter)
        {
            return this.m_LogFilterAttachable.RemoveFilter(filter);
        }

        /// <summary>
        /// 清除所有的日志过滤器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:17    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public void ClearFilters()
        {
            this.m_LogFilterAttachable.ClearFilters();
        }

        #endregion

        #region ---IDisposable

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:00    创建
        /// </history>
        public void Dispose()
        {
            //释放托管资源
            this.Dispose(true);

            //阻止回收
            GC.SuppressFinalize(this);
        }

        #endregion

        #region ---Public Method

        /// <summary>
        /// 返回表示当前<see cref="AbstractLogAppender"/>对象的<see cref="String"/>对象
        /// </summary>
        /// <returns>
        /// 表示当前<see cref="AbstractLogAppender"/>对象的<see cref="String"/>对象
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/16 11:24    创建
        /// </history>
        public override string ToString()
        {
            return string.Format("Appender:{0}", this.m_Name);
        }

        #endregion

        #region ---Property

        /// <summary>
        /// 获得或者设置
        /// </summary>
        /// <value></value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:34    创建
        /// </history>
        public ILogErrorHandler ErrorHandler
        {
            get
            {
                //判断日志错误处理器是否设置
                if (null == this.m_ErrorHandler)
                {
                    //返回默认的日志错误处理器
                    return LoggingContext.ErrorHandler;
                }

                //返回日志错误处理器
                return this.m_ErrorHandler;
            }
            set
            {
                //设置日志错误处理器
                this.m_ErrorHandler = value;
            }
        }

        /// <summary>
        /// 获得或者设置允许输出的最低级别日志
        /// </summary>
        /// <value>允许输出的最低级别日志</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:56    创建
        /// </history>
        public Level MinLevel
        {
            get
            {
                return this.m_MinLevel;
            }
            set
            {
                this.m_MinLevel = value;
            }
        }

        /// <summary>
        /// 获得或者设置允许输出的最高级别日志
        /// </summary>
        /// <value>允许输出的最高级别日志</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:56    创建
        /// </history>
        public Level MaxLevel
        {
            get
            {
                return this.m_MaxLevel;
            }
            set
            {
                this.m_MaxLevel = value;
            }
        }

        /// <summary>
        /// 获得或者设置是否将缓冲区的数据写入到物理数据存储区
        /// </summary>
        /// <value>
        /// 	<c>true</c>：立即写入<br/>
        /// 	<c>false</c>：不立即写入
        /// </value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:17    创建
        /// </history>
        public bool AutoFlush
        {
            get
            {
                return this.m_AutoFlush;
            }
            set
            {
                this.m_AutoFlush = value;
            }
        }

        /// <summary>
        /// 获得用于日志记录器创建同步区域所用的同步上下文
        /// </summary>
        /// <value>用于日志记录器创建同步区域所用的同步上下文</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/14 9:12    创建
        /// </history>
        protected ISynchronizationContext SynchronizationContext
        {
            get
            {
                //获得同步上下文
                ISynchronizationContext context = this.GetSynchronizationContext();

                //返回同步上下文
                return (null == context) ? NullSynchronizationContext.Default : context;
            }
        }

        #endregion

        #region ---Protected Method

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务
        /// </summary>
        /// <param name="disposing">是否释放托管资源</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:01    创建
        /// </history>
        protected virtual void Dispose(bool disposing)
        {
            //关闭日志输出器
            this.Close();
        }

        /// <summary>
        /// 将缓冲区的数据写入到物理数据存储区
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:15    创建
        /// </history>
        protected virtual void Flush()
        {
        }

        /// <summary>
        /// 通知关闭日志输出器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:06    创建
        /// </history>
        protected abstract void OnClose();

        /// <summary>
        /// 通知输出给定的日志条目
        /// </summary>
        /// <param name="entry">要输出的日志条目</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:26    创建
        /// </history>
        protected abstract void OnAppend(LogEntry entry);

        /// <summary>
        /// 判断给定级别的日志是否允许输出
        /// </summary>
        /// <param name="level">用于判断的日志级别</param>
        /// <returns>
        /// 	<c>true</c>：允许输出<br/>
        /// 	<c>false</c>：不允许输出
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:57    创建
        /// </history>
        protected virtual bool IsLevelAllowed(Level level)
        {
            //判断日志级别是否为NULL
            if (null == level)
            {
                //如果日志级别为NULL，则总是不允许
                return false;
            }

            //判断是否设置了最低日志级别，并且日志级别是否低于最低要求基本
            if (null != this.m_MinLevel && level < this.m_MinLevel)
            {
                return false;
            }

            //判断是否设置了最高日志级别，并且日志级别是否高于最低要求基本
            if (null != this.m_MaxLevel && level > this.m_MaxLevel)
            {
                return false;
            }

            //默认返回允许
            return true;
        }

        /// <summary>
        /// 判断指定的日志条目是否允许输出
        /// </summary>
        /// <param name="entry">用于判断的日志条目</param>
        /// <returns>
        /// 	<c>true</c>：允许输出<br/>
        /// 	<c>false</c>：不允许输出
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 16:01    创建
        /// </history>
        protected virtual bool IsLogEntryAllowed(LogEntry entry)
        {
            //判断日志条目是否为NULL
            if (null == entry)
            {
                //如果日志条目为NULL，则总是不允许
                return false;
            }

            //循环调用过滤器判断
            foreach (ILogFilter filter in this.Filters)
            {
                //判断是否拒绝
                if (filter.Decide(entry) == FilterDecisionEnum.Deny)
                {
                    //如果拒绝，则认为不批准
                    return false;
                }
            }

            //默认允许
            return true;
        }

        /// <summary>
        /// 通知准备输出给定的日志条目
        /// </summary>
        /// <param name="entry">要输出的日志条目</param>
        /// <returns>
        /// 	<c>True</c>：允许输出给定的日志条目<br/>
        /// 	<c>False</c>：不允许输出给定的日志条目
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 9:25    创建
        /// </history>
        protected virtual bool OnBeforeAppend(LogEntry entry)
        {
            return true;
        }

        /// <summary>
        /// 通知给定的日志条目已经输出
        /// </summary>
        /// <param name="entry">输出的日志条目</param>
        /// <param name="IsCanceled">是否取消了给定日志条目的输出</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 9:40    创建
        /// </history>
        protected virtual void OnAfterAppend(LogEntry entry, bool IsCanceled)
        {
        }

        /// <summary>
        /// 获得用于日志记录器创建同步区域所用的同步上下文
        /// </summary>
        /// <returns>用于日志记录器创建同步区域所用的同步上下文</returns>
        /// <remarks>默认返回空白同步上下文</remarks>
        /// <history>
        /// [zanezeng]               2010/1/6 10:21    创建
        /// </history>
        protected virtual ISynchronizationContext GetSynchronizationContext()
        {
            //默认返回空白同步上下文
            return NullSynchronizationContext.Default;
        }

        #endregion

        #region ---Field

        /// <summary>
        /// 日志输出器的名称
        /// </summary>
        private string m_Name;

        /// <summary>
        /// 当前日志输出器是否可用
        /// </summary>
        private bool m_IsEnabled = true;

        /// <summary>
        /// 用于记录日志输出器是否已经关闭
        /// </summary>
        private bool m_IsClosed;

        /// <summary>
        /// 过滤器附加器
        /// </summary>
        private ILogFilterAttachable m_LogFilterAttachable = new LogFilterAttachableImplement();

        /// <summary>
        /// 日志框架内部错误处理器
        /// </summary>
        private ILogErrorHandler m_ErrorHandler;

        /// <summary>
        /// 允许输出的最低级别日志
        /// </summary>
        private Level m_MinLevel;

        /// <summary>
        /// 允许输出的最高级别日志
        /// </summary>
        private Level m_MaxLevel;

        /// <summary>
        /// 是否立即将缓冲区的数据写入到物理数据存储区
        /// </summary>
        private bool m_AutoFlush;

        #endregion
    }
}
